Skip to content

S01-06 基础-数组

[TOC]

概述

为什么需要数组

一个养鸡场有 6 只鸡,它们的体重分别是 3kg、5kg、1kg、3.4kg、2kg、50kg 。请问这六只鸡的总体重是多少?平均体重是多少?请你编一个程序(Array01.java)

思路:定义 6 个变量,加起来求总体重,进而求出平均体重。引出-> 数组

数组介绍

数组:是一种引用数据类型,用于存储固定长度相同数据类型的元素集合。它将多个同类型的变量按连续的内存地址组织起来,通过 下标(索引) 快速访问每个元素,是处理批量同类型数据的基础结构。

即:数(数据)组(一组)就是一组数据

快速入门:养鸡场

比如,我们可以用数组来解决上一个问题,体验数组的使用:

java
public class Array01 {
    //编写一个main方法
    public static void main(String[] args) {
        /*
        它们的体重分别是3kg,5kg,1kg,3.4kg,2kg,50kg 。
        请问这六只鸡的总体重是多少?平均体重是多少?
        思路分析
        1. 定义六个变量double , 求和得到总体重
        2. 平均体重= 总体重/ 6
        3. 分析传统实现的方式问题:6->600->566
        4. 引出新的技术-> 使用数组来解决.
        */
        // 传统方式实现(注释掉,用于对比)
        // double hen1 = 3;
        // double hen2 = 5;
        // double hen3 = 1;
        // double hen4 = 3.4;
        // double hen5 = 2;
        // double hen6 = 50;
        // double totalWeight = hen1 + hen2 + hen3 + hen4 + hen5 + hen6;
        // double avgWeight = totalWeight / 6;
        // System.out.println("总体重=" + totalWeight + " 平均体重=" + avgWeight);

        // 用数组解决
        // 老韩解读
        // 1. double[] 表示是double类型的数组,数组名hens
        // 2. {3, 5, 1, 3.4, 2, 50, 7.8, 88.8, 1.1, 5.6, 100} 表示数组的值/元素,依次对应数组的各个元素
        double[] hens = {3, 5, 1, 3.4, 2, 50, 7.8, 88.8, 1.1, 5.6, 100};

        System.out.println("===使用数组解决===");
        // 老师提示:可以通过数组名.length 得到数组的大小/长度
        // System.out.println("数组的长度=" + hens.length);

        double totalWeight = 0;
        // 遍历数组得到所有元素的和
        // 老韩解读
        // 1. 可以通过hens[下标] 访问数组的元素,下标从0开始(第一个元素hens[0],第二个hens[1],依次类推)
        // 2. 通过for循环访问数组的所有元素
        // 3. 使用变量totalWeight累积各个元素的值
        for (int i = 0; i < hens.length; i++) {
            // System.out.println("第" + (i+1) + "个元素的值=" + hens[i]);
            totalWeight += hens[i];
        }

        System.out.println("总体重=" + totalWeight + " 平均体重=" + (totalWeight / hens.length));
    }
}

数组基础

数组初始化

方式 1:动态初始化-声明时赋值

语法

java
// 语法
数据类型 数组名[] = new 数据类型[大小]

// 示例:
int a[] = new int[5]; // 创建了一个int类型数组,名字a,可存放5个int值

说明:这是定义数组的一种方法,结合数组内存图理解

image-20251216164223913

示例:快速入门

循环输入 5 个成绩,保存到 double 数组,并输出:

java
import java.util.Scanner;

public class Array02 {
    public static void main(String[] args) {
        // 演示动态初始化数组
        // 循环输入5个成绩,保存到double数组,并输出

        // 步骤
        // 1. 创建double数组,大小5
        // (1) 第一种动态分配方式:double scores[] = new double[5];
        // (2) 第二种动态分配方式:先声明数组,再分配内存空间
        double scores[]; // 声明数组,此时scores是null
        scores = new double[5]; // 分配内存空间,可存放5个double数据

        // 2. 循环输入成绩
        Scanner myScanner = new Scanner(System.in);
        for (int i = 0; i < scores.length; i++) {
            System.out.println("请输入第" + (i+1) + "个成绩:");
            scores[i] = myScanner.nextDouble();
        }

        // 3. 输出数组元素
        System.out.println("==数组的元素/值的情况如下:===");
        for (int i = 0; i < scores.length; i++) {
            System.out.println("第" + (i+1) + "个元素的值=" + scores[i]);
        }
    }
}

方式 2:动态初始化-先声明再赋值

  1. 声明数组

    java
    // 语法
    数据类型 数组名[];
    数据类型[] 数组名;
    
    // 示例
    int a[];
    int[] a;
  2. 创建数组(分配内存)

    java
    // 语法
    数组名 = new 数据类型[大小];
    
    // 示例
    a = new int[10];

案例演示:基于前面的代码修改即可

方式 3:静态初始化

语法

如果已知数组的元素个数和具体值,可直接使用静态初始化。

等价于:先创建指定大小的数组,再逐个给元素赋值。

java
数据类型 数组名[] = {元素值1, 元素值2, ..., 元素值n};

示例

java
// 静态初始化
int a[] = {2,5,6,7,8,89,90,34,56};

// 等价于动态初始化的如下写法
int a[] = new int[9];
a[0] = 2; a[1] = 5; a[2] = 6; a[3] = 7; a[4] = 8;
a[5] = 89; a[6] = 90; a[7] = 34; a[8] = 56;

// 养鸡场案例中的数组(静态初始化)
double hens[] = {3, 5, 1, 3.4, 2, 50};
// 等价于
double hens[] = new double[6];
hens[0] = 3; hens[1] = 5; hens[2] = 1; hens[3] = 3.4; hens[4] = 2; hens[5] = 50;

数组的访问

语法

java
// 语法
数组名[下标/索引/index]

// 示例:
a[2] // 访问a数组的第3个元素,数组下标从0开始

数组核心特性

  1. 数组是多个相同类型数据的组合,实现对这些数据的统一管理。

  2. 数组中的元素可以是任何数据类型(包括基本类型和引用类型),但不能混用

  3. 数组创建后如果没有赋值,会有默认值

    • 基本类型:
      • int 0short 0byte 0long 0
      • float 0.0double 0.0
      • char \u0000
      • boolean false
    • 引用类型(如 String):null
  4. 使用数组的步骤:

    1. 声明数组并开辟空间
    2. 给数组元素赋值
    3. 使用数组
  5. 数组的下标从0开始。

  6. 数组下标必须在指定范围内使用(有效范围:0 ~ length-1),否则报下标越界异常

    java
    // 有效下标为0-4,访问 arr[5] 会报错
    int[] arr = new int[5];
  7. 数组属于引用类型,数组型数据是对象(object)。

示例:验证代码

java
public class ArrayDetail {
    //编写一个main方法
    public static void main(String[] args) {
        // 1. 数组元素类型必须相同(错误示例:int数组中不能放String)
        // int[] arr1 = {1, 2, 3, 60, "hello"}; // 编译错误:String无法转换为int
        double[] arr2 = {1.1, 2.2, 3.3, 60.6, 100}; // 正确:int自动转换为double

        // 2. 数组元素可以是引用类型(示例:String数组)
        String[] arr3 = {"北京", "jack", "milan"};

        // 3. 数组未赋值时的默认值
        short[] arr4 = new short[3];
        System.out.println("=====数组arr4(未赋值的默认值)=====");
        for (int i = 0; i < arr4.length; i++) {
            System.out.println(arr4[i]); // 输出3个0(short类型默认值)
        }

        // 6. 数组下标越界演示(注释掉,避免运行报错)
        // int[] arr = new int[5];
        // System.out.println(arr[5]); // 运行时异常:ArrayIndexOutOfBoundsException
    }
}

数组应用

应用 1:创建 26 个字母数组

创建一个 char 类型的 26 个元素的数组,分别放置'A'-'Z',使用 for 循环访问所有元素并打印。

提示:char 类型支持运算('A' + 2 → 'C'

java
public class ArrayExercise01 {
    public static void main(String[] args) {
        /*
        思路分析
        1. 定义char数组,大小26
        2. 利用'A' + i 的运算赋值(i从0到25)
        3. 循环访问并打印所有元素
        */
        char[] chars = new char[26];
        // 赋值:A~Z
        for (int i = 0; i < chars.length; i++) {
            // 'A' + i 是int类型,需要强制转换为char
            chars[i] = (char) ('A' + i);
        }
        // 输出
        System.out.println("===chars数组===");
        for (int i = 0; i < chars.length; i++) {
            System.out.print(chars[i] + " "); // 输出:A B C ... Z
        }
    }
}

应用 2:求数组最大值及下标

请求出数组int[] arr = {4, -1, 9, 10, 23}的最大值,并得到对应的下标。

java
public class ArrayExercise02 {
    //编写一个main方法
    public static void main(String[] args) {
        /*
        老韩思路分析
        1. 定义目标数组
        2. 假定第一个元素为最大值(max = arr[0]),下标为maxIndex=0
        3. 从下标1开始遍历数组,若当前元素>max,则更新max和maxIndex
        4. 遍历结束后,max即为最大值,maxIndex为对应下标
        */
        int[] arr = {4, -1, 9, 10, 23};
        int max = arr[0]; // 假定第一个元素是最大值
        int maxIndex = 0; // 最大值的初始下标

        // 从下标1开始遍历
        for (int i = 1; i < arr.length; i++) {
            if (max < arr[i]) { // 若当前元素大于max
                max = arr[i]; // 更新最大值
                maxIndex = i; // 更新最大值下标
            }
        }

        System.out.println("max=" + max + " maxIndex=" + maxIndex); // 输出:max=23 maxIndex=4
    }
}

应用 3:求数组的和和平均值

基于养鸡场案例,直接通过数组遍历求和,再计算平均值(已在 Array01.java 中实现)。

对象数组

什么是对象数组

在 Java 中,对象数组(Object Array) 是一个非常基础但也极其容易让初学者踩坑的概念。

简单来说:如果说普通数组(如 int[])是一个装满数字的盒子,那么对象数组就是一个装满“遥控器”的盒子,每个遥控器分别指向一台真正的“电视机”(对象)。

本质它存的是内存地址的引用

在 Java 中,基本数据类型(如 int, double)和引用数据类型(如 String, 自定义类)在内存中的存储方式完全不同。

  • 基本类型数组(如 int[]:数组的每个格子里,直接存着具体的数值(比如 10, 20)。
  • 对象类型数组(如 User[]:数组的每个格子里,存的仅仅是内存地址(引用),而不是真正的对象。

创建对象数组

创建对象数组的“标准三步曲”:

这是新手最容易犯错的地方。创建一个对象数组,必须经历完整的三个步骤,缺一不可:

  1. 步骤 1:定义一个类(设计图纸):

    假设我们有一个简单的 Student 类:

    java
    class Student {
        String name;
        int age;
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
  2. 步骤 2:创建数组(造盒子):

    java
    // 声明并创建一个长度为 3 的 Student 数组
    Student[] students = new Student[3];

    ** 极其重要**:执行完这句代码后,内存中只是有了 3 个位置,但这 3 个位置里全部都是 null。这时候如果你直接去调用 students[0].name,程序会立刻抛出 NullPointerException(空指针异常)!

  3. 步骤 3:实例化对象并放入数组(买电视并配对遥控器):

    你必须挨个(或通过循环)把真正的对象 new 出来,放进数组的格子里:

    java
    students[0] = new Student("张三", 18);
    students[1] = new Student("李四", 20);
    students[2] = new Student("王五", 19);

    或者,你可以使用静态初始化一步到位,代码更简洁:

    java
    Student[] students = {
        new Student("张三", 18),
        new Student("李四", 20),
        new Student("王五", 19)
    };

image-20260302145131819

遍历对象数组

遍历对象数组与普通数组没有区别,强烈推荐使用你之前了解过的 Foreach 增强型循环

java
for (Student stu : students) {
    // 每次循环,stu 就会指向数组中的下一个真实对象
    System.out.println("姓名:" + stu.name + ",年龄:" + stu.age);
}

致命缺陷

对象数组的致命缺陷:

虽然对象数组是 Java 底层不可或缺的基础,但在现代的实际业务开发中,我们极少直接使用对象数组,原因有两点:

  1. 长度固定死板:一旦你声明了 new Student[3],这个数组就永远只能装 3 个人。如果中途转学来了一个新同学,你无法把他直接塞进去,只能重新建一个更大的数组,再把老数据搬过去,非常麻烦。

  2. 功能匮乏:数组没有自带好用的方法,比如“删除某个元素”、“判断是否包含某个对象”等,都需要你自己手写循环去实现。

现代替代方案

因为上述缺陷,日常开发中我们几乎总是使用 集合(如 ArrayList<Student> 来替代对象数组。ArrayList 底层其实也就是一个对象数组,只不过 Java 帮我们封装好了自动扩容、增删改查的所有逻辑。

数组操作

数组赋值机制

基本类型赋值

赋值的是具体的数据,两个变量相互独立,修改一个不影响另一个。

java
int n1 = 2;
int n2 = n1;
n2 = 80;
System.out.println("n1=" + n1); // 输出10(不受n2修改影响)
System.out.println("n2=" + n2); // 输出80

引用赋值

数组默认是引用传递,赋值的是数组的地址,两个数组变量指向同一个内存空间。

修改其中一个数组的元素,会影响另一个数组。


示例

java
public class ArrayAssign {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3};
        int[] arr2 = arr1; // 引用传递:arr2指向arr1的内存地址

        arr2[0] = 10; // 修改arr2的元素

        // 输出arr1和arr2的元素
        System.out.println("====arr1的元素====");
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]); // 输出:10, 2, 3(arr1的元素被修改)
        }
        System.out.println("====arr2的元素====");
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(arr2[i]); // 输出:10, 2, 3
        }
    }
}

内存解析

  • 栈内存:存储变量(arr1、arr2),保存数组的内存地址(如 0x0011)。
  • 堆内存:存储数组的实际元素(1,2,3),地址为 0x0011。
  • arr1 和 arr2 都指向 0x0011,修改 arr2[0]本质是修改堆内存中数组的元素。

image-20251216164932336

数组拷贝

要求:实现数组内容的复制,新数组与原数组的数据空间独立(修改新数组不影响原数组)。

java
public class ArrayCopy {
    //编写一个main方法
    public static void main(String[] args) {
        // 原数组
        int[] arr1 = {10, 20, 30};

        // 1. 创建新数组,开辟独立的内存空间(大小与原数组一致)
        int[] arr2 = new int[arr1.length];

        // 2. 遍历原数组,将元素逐个拷贝到新数组
        for (int i = 0; i < arr1.length; i++) {
            arr2[i] = arr1[i];
        }

        // 修改新数组的元素(验证独立性)
        arr2[0] = 100;

        // 输出原数组(不受影响)
        System.out.println("====arr1的元素====");
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]); // 输出:10, 20, 30
        }

        // 输出新数组(已修改)
        System.out.println("====arr2的元素====");
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(arr2[i]); // 输出:100, 20, 30
        }
    }
}

数组反转

要求:将数组元素反转(如{11,22,33,44,55,66}{66,55,44,33,22,11}

方式 1:原地反转

思路分析

  1. 交换规律:arr[i]arr[arr.length - 1 - i] 交换(i 从 0 开始)。
  2. 交换次数:arr.length / 2(如 6 个元素交换 3 次,5 个元素交换 2 次)。

代码实现

java
public class ArrayReverse {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44, 55, 66};
        int temp = 0; // 辅助交换的临时变量
        int len = arr.length; // 数组长度(优化:避免重复计算)

        // 交换逻辑
        for (int i = 0; i < len / 2; i++) {
            temp = arr[len - 1 - i]; // 保存末尾元素
            arr[len - 1 - i] = arr[i]; // 前面元素移到末尾
            arr[i] = temp; // 末尾元素移到前面
        }

        // 输出反转后的数组
        System.out.println("===翻转后数组===");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t"); // 输出:66	55	44	33	22	11
        }
    }
}

方式 2:逆序赋值

思路分析

  1. 创建与原数组大小相同的新数组arr2
  2. 逆序遍历原数组,将元素依次赋值给新数组的正序位置。
  3. 让原数组变量arr指向新数组(原数组内存空间变为垃圾,被 JVM 回收)。

image-20251216165041752

代码实现

java
public class ArrayReverse02 {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44, 55, 66};
        // 创建新数组
        int[] arr2 = new int[arr.length];

        // 逆序遍历原数组,赋值给新数组
        for (int i = arr.length - 1, j = 0; i >= 0; i--, j++) {
            arr2[j] = arr[i];
        }

        // 原数组变量指向新数组
        arr = arr2;

        // 输出结果
        System.out.println("====arr的元素情况=====");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t"); // 输出:66	55	44	33	22	11
        }
    }
}

数组扩容@

要求:实现动态给数组添加元素,支持用户自主选择是否继续添加(ArrayAdd02.java)

需求

  1. 原始数组:int[] arr = {1,2,3}(静态分配)。
  2. 每次添加元素到数组末尾(如添加 4 → {1,2,3,4})。
  3. 提示用户输入添加的元素,添加成功后询问是否继续(y/n)。

思路分析

  1. 每次添加时,创建新数组(大小=原数组长度+1)。
  2. 将原数组元素拷贝到新数组。
  3. 新元素赋值给新数组的最后一个位置。
  4. 原数组变量指向新数组(完成扩容)。
  5. 使用do-while循环+break控制用户输入逻辑。

image-20260226115601132

代码实现

java
import java.util.Scanner;

public class ArrayAdd02 {
  public static void main(String[] args) {
    Scanner myScanner = new Scanner(System.in);
    // 初始化原数组
    int[] arr = {1, 2, 3};

    // 1. 创建新数组(扩容为5)
    int[] arrNew = new int[5];

    // 2. 拷贝原数组元素到新数组
    for (int i = 0; i < arr.length; i++) {
      arrNew[i] = arr[i];
    }

    // 3. 原数组指向新数组
    arr = arrNew;

    // 4. 新元素放入新数组末尾(可选)
    arr[3] = 4;
    arr[4] = 5;

    // 5. 输出扩容后的数组
    System.out.println("====arr扩容后元素情况====");
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + "\t");
    }
  }
}

数组合并

需求:合并数组 {1,2,3}{4,5,6}

image-20260226154211638

代码实现

image-20260226154416980

练习:数组缩减

需求:有一个数组{1,2,3,4,5},提示用户是否继续缩减,每次缩减最后一个元素。当只剩最后一个元素时,提示“不能再缩减”。

image-20251216165144848

二维数组

多维数组中最常用的是二维数组,应用场景如:五子棋棋盘(行列坐标)、表格数据等。

快速入门

需求:用二维数组输出如下图形:

0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0

代码实现

java
public class TwoDimensionalArray01 {
    public static void main(String[] args) {
        /*
        二维数组定义:
        1. 从形式上看:int[][] 表示二维数组(一维数组的每个元素是一维数组)
        2. 初始化:{ {0,0,0,0,0,0}, {0,0,1,0,0,0}, {0,2,0,3,0,0}, {0,0,0,0,0,0} }
        */
        int[][] arr = {
                {0, 0, 0, 0, 0, 0},
                {0, 0, 1, 0, 0, 0},
                {0, 2, 0, 3, 0, 0},
                {0, 0, 0, 0, 0, 0}
        };

        // 二维数组的关键概念
        System.out.println("二维数组的元素个数(一维数组的个数)=" + arr.length); // 输出4(4个一维数组)
        // 访问指定元素:第3个一维数组的第4个值(arr[2][3],下标从0开始)
        System.out.println("第3个一维数组的第4个值=" + arr[2][3]); // 输出3

        // 遍历二维数组(嵌套循环)
        System.out.println("===二维数组图形输出===");
        for (int i = 0; i < arr.length; i++) { // 遍历二维数组的每个一维数组
            for (int j = 0; j < arr[i].length; j++) { // 遍历当前一维数组的每个元素
                System.out.print(arr[i][j] + " ");
            }
            System.out.println(); // 换行
        }
    }
}

初始化

方式 1:动态初始化-固定行列

语法

java
类型[][] 数组名 = new 类型[行数][列数]

示例

java
public class TwoDimensionalArray02 {
    public static void main(String[] args) {
        // 方式1:直接初始化
        // int[][] arr = new int[2][3]; // 2行3列的二维数组

        // 方式2:先声明,再分配空间
        int[][] arr;
        arr = new int[2][3]; // 2个一维数组,每个一维数组有3个元素
        arr[1][1] = 8; // 给第2行第2列的元素赋值8

        // 遍历二维数组
        System.out.println("===二维数组输出===");
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}

内存解析

  • 栈内存arr 存储二维数组的地址(如 0x0011)。
  • 堆内存
    • 二维数组(地址 0x0011)存储两个一维数组的地址(如 0x0022、0x0033)。
    • 一维数组(0x0022):[0,0,0](默认值)。
    • 一维数组(0x0033):[0,8,0](arr[1][1]赋值为 8)。

image-20251216165917783

方式 3:动态初始化-列数不确定

需求:动态创建如下二维数组(每行列数不同),并输出:

i=0: 1
i=1: 2 2
i=2: 3 3 3

思路分析

  1. 创建二维数组时,只指定行数(3 行),不指定列数。
  2. 遍历每行,为每行的一维数组分配不同的列数(第 i 行分配 i+1 列)。
  3. 给每行的元素赋值(第 i 行的元素值为 i+1)。

代码实现

java
public class TwoDimensionalArray03 {
    public static void main(String[] args) {
        // 创建二维数组(3行,列数不确定)
        int[][] arr = new int[3][];

        // 为每行分配列数并赋值
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new int[i + 1]; // 第i行分配i+1列(0行1列,1行2列,2行3列)
            // 给当前行的元素赋值
            for (int j = 0; j < arr[i].length; j++) {
                arr[i][j] = i + 1; // 元素值为行号+1
            }
        }

        // 输出二维数组
        System.out.println("=====arr元素=====");
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println(); // 换行
        }
    }
}

方式 4:静态初始化

语法

java
类型[][] 数组名 = { {值1,值2,...}, {值1,值2,...}, ... }

示例

java
// 静态初始化二维数组(3行,列数分别为3、3、1)
int[][] arr = { {1,1,1}, {8,8,9}, {100} };

解读

  • 二维数组arr有 3 个元素(每个元素是一维数组)。
  • 第一个一维数组:[1, 1, 1](3 个元素)。
  • 第二个一维数组:[8, 8, 9](3 个元素)。
  • 第三个一维数组:[100](1 个元素)。

案例:二维数组求和

需求

遍历二维数组int arr[][] = { {4,6}, {1,4,5,7}, {-2} },计算所有元素的和。

代码实现

java
public class TwoDimensionalArray05 {
    public static void main(String[] args) {
        int arr[][] = { {4,6}, {1,4,5,7}, {-2} };
        int sum = 0; // 累积和

        // 嵌套循环遍历二维数组
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                sum += arr[i][j]; // 累加每个元素
            }
        }

        System.out.println("sum=" + sum); // 输出:4+6+1+4+5+7+(-2) = 25
    }
}

案例:打印杨辉三角

杨辉三角规律

  1. 第 1 行有 1 个元素,第 n 行有 n 个元素。
  2. 每行的第一个元素和最后一个元素都是 1。
  3. 从第 3 行开始,中间元素的值 = 上一行同列元素 + 上一行前一列元素(arr[i][j] = arr[i-1][j] + arr[i-1][j-1])。

代码实现:(打印 10 行杨辉三角)

java
public class YangHui {
    public static void main(String[] args) {
        int rows = 10; // 杨辉三角的行数
        int[][] yangHui = new int[rows][]; // 动态初始化二维数组(行数固定,列数不确定)

        // 给杨辉三角赋值
        for (int i = 0; i < yangHui.length; i++) {
            yangHui[i] = new int[i + 1]; // 第i行有i+1个元素
            // 给每行的第一个和最后一个元素赋值1
            yangHui[i][0] = 1;
            yangHui[i][i] = 1;
            // 给中间元素赋值(从第3行开始,i>=2)
            if (i >= 2) {
                for (int j = 1; j < yangHui[i].length - 1; j++) {
                    yangHui[i][j] = yangHui[i-1][j] + yangHui[i-1][j-1];
                }
            }
        }

        // 输出杨辉三角
        System.out.println("===杨辉三角(" + rows + "行)===");
        for (int i = 0; i < yangHui.length; i++) {
            for (int j = 0; j < yangHui[i].length; j++) {
                System.out.print(yangHui[i][j] + "\t");
            }
            System.out.println(); // 换行
        }
    }
}

二维数组注意事项

  1. 一维数组的声明方式int[] xint x[]

  2. 二维数组的声明方式int[][] yint[] y[]int y[][](三种都合法,推荐第一种)。

  3. 二维数组由多个一维数组组成,各个一维数组的长度可以不同(列数不等的二维数组)。

    java
    // map[0]有2个元素,map[1]有3个元素
    int map[][] = { {1,2}, {3,4,5} };

练习

声明int[] x, y[];,以下选项允许通过编译的是(BE)

  • a) x[0] = y; → 错误(int 类型不能接收 int[][]类型)
  • b) y[0] = x; → 正确(int[]类型接收 int[]类型)
  • c) y[0][0] = x; → 错误(int 类型不能接收 int[]类型)
  • d) x[0][0] = y; → 错误(x 是一维数组,x[0][0]语法错误)
  • e) y[0][0] = x[0]; → 正确(int 类型接收 int 类型)
  • f) x = y; → 错误(int[]类型不能接收 int[][]类型)

本章作业

  1. 下面数组定义正确的有(BD)

    • A. String strs[] = {'a','b','c'}; → 错误(字符串数组不能用 char 字面量初始化)
    • B. String[] strs = {"a","b","c"}; → 正确(静态初始化字符串数组)
    • C. String[] strs = new String{"a" "b" "c"}; → 错误(语法错误:缺少逗号和右括号)
    • D. String strs[] = new String[]{"a", "b","c"}; → 正确
    • E. String[] strs = new String[3]{"a", "b", "c"); → 错误(动态初始化指定长度后不能直接赋值元素)
  2. 写出结果

    java
    String foo = "blue";
    boolean[] bar = new boolean[2];
    if (bar[0]) {
        foo = "green";
    }
    System.out.println(foo); // 输出:blue(boolean数组默认值为false,if条件不成立)
  3. 以下 Java 代码的输出结果为()

    java
    int num = 1;
    while (num < 10) {
        System.out.println(num);
        if (num > 5) {
            break;
        }
        num += 2;
    }
    // 输出:1、3、5、7(num=1→3→5→7,7>5触发break)
  4. 有序数组插入元素:已知升序数组[10,12,45,90],插入元素23后保持升序(结果[10,12,23,45,90])。

    实现步骤

    1. 定义原数组和待插入元素:确定升序原数组和需要插入的元素。
    2. 查找插入位置:遍历原数组,找到第一个大于插入元素的位置(即为插入点);若元素比所有元素都大,则插入到数组末尾。
    3. 创建新数组:长度为原数组长度 + 1,用于存储插入后的结果。
    4. 复制元素并插入:将原数组中插入位置前的元素复制到新数组,放入插入元素,再复制插入位置后的元素。
    5. 验证结果:输出新数组,确认升序性。

    代码实现

    java
    // 1. 定义原升序数组和待插入的元素
    int[] arr = {10, 12, 45, 90};
    int insertNum = 23;
    
    // 2. 查找插入位置
    int insertIndex = -1;
    for (int i = 0; i < arr.length; i++) {
        // 找到第一个大于待插入元素的位置,即为插入点
        if (arr[i] > insertNum) {
            insertIndex = i;
            break;
        }
    }
    // 若元素比所有元素都大,插入到数组末尾
    if(insertIndex == -1) insertIndex = arr.length;
    
    // 3. 创建新数组并完成插入
    int[] newArr = new int[arr.length + 1];
    // i:新数组newArr的索引;j:原数组arr的索引
    for(int i=0, j=0; i < newArr.length; i++) {
        if(i != insertIndex) {
            newArr[i] = arr[j];
            j++;
        } else {
            newArr[i] = insertNum;
        }
    }
    
    // 4. 输出结果验证
    System.out.println("原数组:" + Arrays.toString(arr));
    System.out.println("插入元素 " + insertNum + " 后的新数组:" + Arrays.toString(newArr));
  5. 数组综合操作:随机生成 10 个整数(1-100)保存到数组,实现:

    • 倒序打印。
    • 求平均值。
    • 求最大值及下标。
    • 查找是否包含数字 8。
  6. 数组引用传递练习:写出以下代码的打印结果:

    java
    char[] arr1 = {'a','z','b','c'};
    char[] arr2 = arr1;
    arr1[2] = '韩';
    for (int i = 0; i < arr2.length; i++) {
        System.out.println(arr1[i] + "," + arr2[i]);
    }
    // 输出:
    // a,a
    // z,z
    // 韩,韩
    // c,c
  7. 写出冒泡排序的代码:基于冒泡排序案例,独立实现从小到大排序。